package com.zyc.studentstudy.simple

import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.annotation.FloatRange
import androidx.annotation.IdRes
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import com.jetinno.utils.DialogPx
import com.zyc.studentstudy.utils.InputMethodUtil
import com.zyc.studentstudy.utils.ScreenUtil
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import kotlin.coroutines.cancellation.CancellationException

/**
 * Created by zhangyuncai on 2021/7/30.
 */
abstract class SimpleDialogFragment : DialogFragment() {

    val TAG = this::class.java.simpleName

    var isRegisterEventBus = false

    var hiddenSoft = false // dialog显示后，是否隐藏键盘

    //使用懒加载方式得到mContext和mActivity,但不能在onAttach使用这两个字段
    val mContext: Context by lazy { requireContext() }
    val mActivity: FragmentActivity by lazy { requireActivity() }
    lateinit var rootView: View

    var hasFetchData = false // 标识已经触发过懒加载数据

    var mOnDismissListener: DialogInterface.OnDismissListener? = null

    var mSureCallback: ((Any?) -> Unit)? = null

    var mCancelCallback: ((Any?) -> Unit)? = null

    /**
     * 不适用SimpleDialogFragment<T>的另一种方案
     */
    fun <T> setSureCallback(sureCallback: ((T?) -> Unit)?) {
        this.mSureCallback = sureCallback?.let { callback ->//callback就是sureCallback
            { value: Any? ->//let返回一个新增的函数体,对参数做一个安全的强转
                @Suppress("UNCHECKED_CAST")//屏蔽(Unchecked cast: Any? to T)警告
                callback(value as? T)
            }
        }
    }

    fun <T> setCancelCallback(cancelCallback: ((T?) -> Unit)?) {
        this.mCancelCallback = cancelCallback?.let { callback ->
            { value: Any? ->
                @Suppress("UNCHECKED_CAST")//屏蔽(Unchecked cast: Any? to T)警告
                callback(value as? T)
            }
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)
        //这行代码只能放在onCreateDialog,否则报错
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)

        return dialog
    }

    protected open fun useDatabing(inflater: LayoutInflater, container: ViewGroup?): View? {
        return null
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (!::rootView.isInitialized) {
            val bindingView = useDatabing(inflater, container)
            if (bindingView == null) {
                rootView = inflater.inflate(getLayoutId(), container, false)
            } else {
                rootView = bindingView
            }
            rootView.setOnClickListener {
                // 防止事件击穿
            }
        }
        val parent = rootView.parent as? ViewGroup
        parent?.removeView(rootView)

        if (isRegisterEventBus && !EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }

        return rootView
    }

    protected fun <T : View> findViewById(@IdRes id: Int): T {
        return rootView.findViewById(id)
    }

    open val uiNum: Int
        get() = 0

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        findViewByIds()
        dialog?.setCanceledOnTouchOutside(false)
        if (!hasFetchData) {
            hasFetchData = true
            initView()
            initEvent()
            initData()
        }
    }

    open fun findViewByIds() {}

    protected abstract fun getLayoutId(): Int

    protected abstract fun initView()

    protected abstract fun initEvent()

    protected abstract fun initData()

    protected fun runOnUiThread(runnable: Runnable) {
        activity?.runOnUiThread(runnable)
    }

    /**
     * 延时一段时间收到消息
     * @param time 延时时间,毫秒
     * @param callback 延时时间已到回调
     */
    protected fun delayTime(time: Long, callback: ((Boolean) -> Unit)): Job {
        return lifecycleScope.launch {
            try {
                delay(time)
                callback.invoke(true)
            } catch (e: CancellationException) {
                // 静默处理取消异常，不打印日志
            } catch (throwable: Throwable) {
            }
        }
    }

    override fun show(manager: FragmentManager, tag: String?) {
        try {
            // 在每个add事务前增加一个remove事务，防止连续的add
            manager.beginTransaction().remove(this).commit()
            super.show(manager, tag)
        } catch (e: Exception) {
        }
    }

    override fun dismiss() {
        super.dismiss()
    }

    override fun onStart() {
        super.onStart()
        val dialog = dialog
        val window = dialog?.window ?: return

        // 设置窗体背景色透明
        window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        if (hiddenSoft) {
            window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
        }

        // 设置宽度为屏宽, 靠近屏幕底部。
        val layoutParams = window.attributes
        layoutParams.width = getWidthStyle()
        layoutParams.height = getHeightStyle()
        layoutParams.gravity = getGravity()
        layoutParams.dimAmount = getDimAmout() // 设置黑暗度
        window.attributes = layoutParams
    }

    protected open fun getDimAmout(): Float {
        return 0.8f
    }

    override fun onDestroyView() {
        super.onDestroyView()
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this)
        }
        hasFetchData = false
        closeKeyBoard()
    }

    protected fun closeKeyBoard() {
        InputMethodUtil.closeKeyBoard(mActivity)
    }

    @FloatRange(from = 0.0, to = 1.0)
    protected open fun getWidthPercent(): Double {
        return DialogPx.getWidthPercent()
    }

    protected open fun getWidthStyle(): Int {
        val widthPercent = getWidthPercent()
        return if (widthPercent > 0 && widthPercent < 1) {
            (ScreenUtil.getScreenWidth(mContext) * widthPercent).toInt()
        } else {
            WindowManager.LayoutParams.MATCH_PARENT
        }
    }

    @FloatRange(from = 0.0, to = 1.0)
    protected open fun getHeightPercent(): Double {
        return DialogPx.getHeightPercent()
    }

    protected open fun getHeightStyle(): Int {
        val heightPercent = getHeightPercent()
        return if (heightPercent > 0 && heightPercent < 1) {
            (ScreenUtil.getScreenHeight(mContext) * heightPercent).toInt()
        } else {
            WindowManager.LayoutParams.WRAP_CONTENT
        }
    }

    protected open fun getGravity(): Int {
        return Gravity.CENTER
    }

    fun setOnDismissListener(listener: DialogInterface.OnDismissListener?) {
        this.mOnDismissListener = listener
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        mOnDismissListener?.onDismiss(dialog)
    }

}